/*
 * Copyright 2003-2007 (c) Live Media Pty Ltd. <argot@einet.com.au> 
 *
 * This software is licensed under the Argot Public License 
 * which may be found in the file LICENSE distributed 
 * with this software.
 *
 * More information about this license can be found at
 * http://www.einet.com.au/License
 * 
 * The Developer of this software is Live Media Pty Ltd,
 * PO Box 4591, Melbourne 3001, Australia.  The license is subject 
 * to the law of Victoria, Australia, and subject to exclusive 
 * jurisdiction of the Victorian courts.
 */

package com.colony.remote.rpc;

import java.io.IOException;

import com.argot.TypeException;
import com.argot.TypeInputStream;
import com.argot.TypeMap;
import com.argot.TypeOutputStream;
import com.argot.TypeReader;
import com.argot.TypeWriter;
import com.argot.network.TypeEndPoint;
import com.argot.network.TypeLink;

import com.colony.IContainer;

import com.colony.remote.RemoteException;

public class RpcMetaServer
implements TypeLink
{
	private TypeMap _reference;
	private IContainer _environment;
	private RpcDelegateFactory _delegates;
	private TypeWriter _rpcMetaResponse;
	private TypeReader _rpcMetaRequest;
	
    public RpcMetaServer( RpcDelegateFactory delegates, IContainer environment, TypeMap reference )
    throws TypeException
    {
    	_environment = environment;
        _reference = reference;
        _delegates = delegates;
        _rpcMetaResponse = _reference.getWriter(_reference.getId(RpcMetaResponse.TYPENAME));
        _rpcMetaRequest = _reference.getReader(_reference.getId(RpcMetaRequest.TYPENAME));
    }

	public void processMessage( TypeEndPoint connection ) 
	throws IOException
	{
		RpcMetaMethodRequest request;
		
		// Step 1.  Read the request.
		try
		{
			TypeInputStream sin = new TypeInputStream( connection.getInputStream(), _reference );
			request = (RpcMetaMethodRequest) _rpcMetaRequest.read(sin);
		}
		catch (TypeException e)
		{
			// If there's an error, we have no valid method read from the input stream.
			// Can only throw an IO exception.
			throw new IOException("failed to read RPC request", e );
		}
			
			
		// Step 2.  Find the Object and Process the request.
		Object o = _environment.getObject( request.getLocation() );
		if ( o != null )
		{
		    // Resolve the proxy object.
			RpcDelegate back = _delegates.getBackDelegate( o.getClass() );
	        if ( back != null )
	        {
	        	try
	        	{
	        		back.processRequest( request, o );
	    		}
	    		catch (RemoteException e)
	    		{
	    			request.setException(e);
	    		}
	        	
	        }
	        else
			{
				request.setException( new RemoteException( "no delegate:" + o.getClass().getName() ));
			}
		}
		else
		{
			request.setException( new RemoteException("remote object not found:" + request.getLocation().toString()));
		}

		// Step 3.  Send the response.
		try
		{
			TypeOutputStream tmos = new TypeOutputStream( connection.getOutputStream(), _reference );
			_rpcMetaResponse.write(tmos,request);
		}
		catch (TypeException e)
		{
			// If an error occurs here, there's not much we can do.  If we're on the TypeServer
			// it will send an error response.
			throw new IOException( "failed to write RPC response",e);
		}
	}
	
}
